import { Injectable } from '@nestjs/common';
import { UserActiveTokenManager } from 'my-node-core/security';

import { UserActiveToken } from '../../user-active-tokens/models/user-active-token.model';
import { UserActiveTokensRepository } from '../../user-active-tokens/repositories/user-active-tokens.repository';

@Injectable()
export class UserActiveTokenManagerService implements UserActiveTokenManager {
  private cachedUserActiveTokens: UserActiveToken[] | null = null;
  private reloadCachedUserActiveTokensLock: Promise<void> | null = null;

  constructor(private readonly userActiveTokensRepository: UserActiveTokensRepository) {}

  async getCachedUserActiveTokens(): Promise<UserActiveToken[]> {
    if (this.cachedUserActiveTokens?.length == 0) {
      if (!this.reloadCachedUserActiveTokensLock) {
        this.reloadCachedUserActiveTokensLock = this.reloadCachedUserActiveTokens();
        await this.reloadCachedUserActiveTokensLock;
        this.reloadCachedUserActiveTokensLock = null;
      } else {
        await this.reloadCachedUserActiveTokensLock;
      }
    }

    return this.cachedUserActiveTokens!;
  }

  async reloadCachedUserActiveTokens(): Promise<void> {
    this.cachedUserActiveTokens = await this.userActiveTokensRepository.query();
  }

  async isActiveAccessToken(
    username: string,
    deviceId: string | null,
    accessToken: string,
  ): Promise<boolean> {
    const cachedUserActiveTokens = await this.getCachedUserActiveTokens();

    return cachedUserActiveTokens.some((item) => {
      return (
        item.username == username && item.deviceId == deviceId && item.accessToken == accessToken
      );
    });
  }
}
